package com.ruoyi.common.core.utils.uuid;

/**
 * 雪花算法【生成long类型的id】
 *
 * @author Cao.Yu
 * @date 2021-08-08 22:35
 */
public class SnowIdUtil {
    private long workerId = 1L;
    private long datacenterId = 1L;
    private long sequence = 4095L;
    private long twepoch = 1288834974657L;
    private long workerIdBits = 5L;
    private long datacenterIdBits = 5L;
    private long maxWorkerId = -1L ^ (-1L << workerIdBits);
    private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
    private long sequenceBits = 12L;

    private long workerIdShift = sequenceBits;
    private long datacenterIdShift = sequenceBits + workerIdBits;
    private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
    private long sequenceMask = -1L ^ (-1L << sequenceBits);

    private long lastTimestamp = -1L;

    private static class SnowAssist {
        private static final SnowIdUtil SNOW_OBJECT = new SnowIdUtil();
    }
    public static SnowIdUtil getInstance(){
        return SnowAssist.SNOW_OBJECT;
    }

    private SnowIdUtil() {
    }

    /**
     * @Method genId
     * @Description 生成雪花算法ID
     * @Author Cao.Yu
     * @Date 2024/7/22 13:38
     */
    public static String genSnowId() {
        return SnowIdUtil.getInstance().nextStrId();
    }

    /**
     * @方法名：nextId
     * @描述： 获得下一个Id
     * @作者： Cao.Yu
     * @日期： Created in 2021/3/24 22:21
     */
    public synchronized long nextId() {
        long timestamp = timeGen();

        if (timestamp < lastTimestamp) {
            System.err.printf("clock is moving backwards.  Rejecting requests until %d.", lastTimestamp);
            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds",
                    lastTimestamp - timestamp));
        }

        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0;
        }

        lastTimestamp = timestamp;

        return ((timestamp - twepoch) << timestampLeftShift) |
                (datacenterId << datacenterIdShift) |
                (workerId << workerIdShift) |
                sequence;
    }

    /**
     * @方法名：nextStrId
     * @描述： 获取下一个字符串的雪花id
     * @作者： Cao.Yu
     * @日期： Created in 2021/4/1 21:55
     */
    public synchronized String nextStrId() {
        long timestamp = timeGen();

        if (timestamp < lastTimestamp) {
            System.err.printf("clock is moving backwards.  Rejecting requests until %d.", lastTimestamp);
            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds",
                    lastTimestamp - timestamp));
        }

        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0;
        }

        lastTimestamp = timestamp;

        return String.valueOf(((timestamp - twepoch) << timestampLeftShift) |
                (datacenterId << datacenterIdShift) |
                (workerId << workerIdShift) |
                sequence);
    }

    private long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }
}
